#include <iostream>
#include <map>
#include <memory>
#include <string>

// 基类，产品注册模板接口类
template <class ProductType_t>
class IProductRegistrar {
public:
    virtual std::shared_ptr<ProductType_t> CreateProduct() = 0;

protected:
    IProductRegistrar() = default;
    virtual ~IProductRegistrar() = default;
    IProductRegistrar(const IProductRegistrar&) = delete;
    IProductRegistrar& operator=(const IProductRegistrar&) = delete;
};

// 工厂模板类，用于获取和注册产品对象
template <class ProductType_t>
class ProductFactory {
public:
    static ProductFactory<ProductType_t>& Instance() {
        static ProductFactory<ProductType_t> instance;
        return instance;
    }

    // 产品注册
    void RegisterProduct(IProductRegistrar<ProductType_t>* registrar,
                         std::string name) {
        m_ProductRegistry[name] = registrar;
    }

    // 根据名字，获取对应具体的产品对象
    std::shared_ptr<ProductType_t> GetProduct(std::string name) {
        if (m_ProductRegistry.find(name) != m_ProductRegistry.end()) {
            return m_ProductRegistry[name]->CreateProduct();
        } else {
            return nullptr;
        }
    }

protected:
    ProductFactory() = default;
    ~ProductFactory() = default;
    ProductFactory(const ProductFactory&) = delete;
    ProductFactory& operator=(const ProductFactory&) = delete;

    // 保存注册过的产品，key:产品名字 , value:产品类型
    std::map<std::string, IProductRegistrar<ProductType_t>*> m_ProductRegistry;
};

// 产品注册模板类，用于创建具体产品和从工厂里注册产品
template <class ProductType_t, class ProductImpl_t>
class ProductRegistrar : public IProductRegistrar<ProductType_t> {
public:
    // 构造函数，用于注册产品到工厂，只能显示调用
    explicit ProductRegistrar(std::string name) {
        // 通过工厂单例把产品注册到工厂
        ProductFactory<ProductType_t>::Instance().RegisterProduct(this, name);
    }
    // 创建具体产品对象指针
    std::shared_ptr<ProductType_t> CreateProduct() {
        return std::make_shared<ProductImpl_t>();
    }
};

// 基类 鞋子
class Shoes {
public:
    Shoes() { std::cout << "Shoes build\n"; }

    ~Shoes() { std::cout << "Shoes destroy\n"; }
    virtual void Show() = 0;
};

// 耐克鞋子
class NiKeShoes : public Shoes {
public:
    void Show() { std::cout << "I'm Nike, Just do it\n"; }
    NiKeShoes() { std::cout << "NiKeShoes build\n"; }

    ~NiKeShoes() { std::cout << "NiKeShoes destroy\n"; }
};

// 基类 衣服
class Clothe {
public:
    Clothe() { std::cout << "Clothe build\n"; }

    ~Clothe() { std::cout << "Clothe destroy\n"; }
    virtual void Show() = 0;
};

// 优衣库衣服
class UniqloClothe : public Clothe {
public:
    void Show() { std::cout << "I am Uniqlo\n"; }

    UniqloClothe() { std::cout << "UniqloClothe build\n"; }

    ~UniqloClothe() { std::cout << "UniqloClothe destroy\n"; }
};

int main() {
    {
        // ========================== 生产耐克球鞋过程
        // ===========================//
        ProductRegistrar<Shoes, NiKeShoes> nikeShoes("nike");
        auto pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike");
        auto pNiKeShoes2 = ProductFactory<Shoes>::Instance().GetProduct("nike");

        pNiKeShoes->Show();
    }
    {
        // ========================== 生产优衣库衣服过程
        // ===========================//
        ProductRegistrar<Clothe, UniqloClothe> adidasShoes("uniqlo");
        auto pUniqloClothe =
            ProductFactory<Clothe>::Instance().GetProduct("uniqlo");

        pUniqloClothe->Show();
    }
    return 0;
}